package com.novax.ex.activity.provider.controller;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import com.alibaba.fastjson.JSON;
import com.novax.ex.activity.infrastructure.entity.*;
import com.novax.ex.activity.open.api.TaskApi;
import com.novax.ex.activity.open.model.response.task.*;
import com.novax.ex.activity.provider.common.TaskCenter;
import com.novax.ex.activity.provider.service.*;
import com.novax.ex.common.constant.ActivityConstants;
import com.novax.ex.common.constant.InternationalCode;
import com.novax.ex.common.core.redis.RedisLockUtil;
import com.novax.ex.common.core.redis.RedisUtil;
import com.novax.ex.common.results.ReturnResult;
import com.novax.ex.common.util.CopyUtils;
import com.novax.ex.common.util.JWTUtil;
import com.novax.ex.common.util.PageQuery;
import com.novax.ex.common.util.PageUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.web.bind.annotation.RestController;

import jakarta.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Slf4j
@RestController
public class TaskController extends BaseActivityController implements TaskApi {

    private static final Map<String, Integer> CODE_MAP = new HashMap<String, Integer>() {{
        put(InternationalCode.TWITTER_ID_UNFOLLOW, 1);
        put(InternationalCode.TWITTER_EXIST, 2);
    }};


    @Resource
    private TaskRuleService taskRuleService;
    @Resource
    private TaskTitleService taskTitleService;
    @Resource
    private TaskVersionInfoService taskVersionInfoService;
    @Resource
    private TaskUserProgressService taskUserProgressService;
    @Resource
    private TaskRewardService taskRewardService;
    @Resource
    private TaskAwardLogService taskAwardLogService;
    @Resource
    private TaskEtRewardsService taskEtRewardsService;


    @Override
    public ReturnResult<TaskModuleResponse> newbie(String token, String language) {

        TaskModuleResponse response;
        List<TaskTitleLanguage> taskTitles = taskTitleService.findTaskTitleByLanguage(language);
        List<TaskTitleLanguage> englist = taskTitleService.findTaskTitleByLanguage("en");

        for (int i = 0; i < taskTitles.size(); i++) {
            if (StringUtils.isBlank(taskTitles.get(i).getTitle()) || StringUtils.isBlank(taskTitles.get(i).getContent())) {
                taskTitles.get(i).setTitle(englist.get(i).getTitle());
                taskTitles.get(i).setContent(englist.get(i).getContent());
            }
        }

        List<TaskModuleDto> dto = CopyUtils.copyList(taskTitles, TaskModuleDto.class).stream()
                .sorted(Comparator.comparingInt(TaskModuleDto::getStep))
                .collect(Collectors.toList());

        // 是否展示新手引导
        if (ObjectUtils.isEmpty(token) || Objects.isNull(JWTUtil.getUid(token))) {
            dto.forEach(item -> item.setIsCompleted(TaskCenter.UN_FINISH));
            response = new TaskModuleResponse();
            response.setDto(dto);
            response.setIsShow(TaskCenter.SHOW);
        } else {
            List<TaskModuleDto> collect = null;
            Long uid = JWTUtil.getUid(token);
            int step = taskUserProgressService.findStepByUid(uid);
            Boolean oldUser = taskVersionInfoService.isOldUser(uid);

            if (step == TaskCenter.MAX_STEP) {
                // 如果签到任务完成，倒叙排列
                collect = dto.stream()
                        .sorted(Comparator.comparingInt(TaskModuleDto::getStep).reversed())
                        .collect(Collectors.toList());
                // 最后一步永远不能完成，用户可以点击去分享邀请好友
                collect.forEach(item -> {
                    if (Objects.equals(item.getStep(), TaskCenter.STEP_FIVE)) {
                        item.setIsCompleted(TaskCenter.UN_FINISH);
                    } else {
                        item.setIsCompleted(TaskCenter.FINISH);
                    }
                });
            }

            if (step < TaskCenter.MAX_STEP) {
                // 如果用户未完成签到任务
                // 老用户前三步直接设置为完成状态 新用户完成前三步的也设置为完成状态
                if (oldUser || step >= TaskCenter.STEP_FOUR) {
                    dto.forEach(item -> {
                        if (item.getStep() <= TaskCenter.STEP_THREE) {
                            item.setIsCompleted(TaskCenter.FINISH);
                        } else {
                            item.setIsCompleted(TaskCenter.UN_FINISH);
                        }
                    });
                } else {
                    dto.forEach(item -> {
                        if (item.getStep() <= step) {
                            item.setIsCompleted(TaskCenter.FINISH);
                        } else {
                            item.setIsCompleted(TaskCenter.UN_FINISH);
                        }
                    });
                }
                collect = dto;
            }

            // 设置老用户不能看见新手引导的前三步，新用户可以
            response = new TaskModuleResponse();
            response.setDto(collect);
            if (oldUser) {
                response.setIsShow(TaskCenter.NOT_SHOW);
                // 如果是老用户就不展示
                response.setIsShowIcon(TaskCenter.NOT_SHOW);
            } else {
                // UE7期优化(在原有新老用户逻辑的基础上，判断用户是否入金，如果有入金记录，则判定为老用户)
                if (taskVersionInfoService.finishDepositV1(uid, TaskCenter.NOT_TRAD_TODAY, 1)) {
                    response.setIsShowIcon(TaskCenter.NOT_SHOW);
                } else {
                    response.setIsShowIcon(TaskCenter.SHOW);
                }
                response.setIsShow(TaskCenter.SHOW);
            }
        }
        return ReturnResult.success(response);
    }

    @Override
    public ReturnResult<?> taskRule(String language) {
        String taskRule = taskRuleService.getTaskRule(language);
        return ReturnResult.success(getInternational(language, InternationalCode.QUERY_SUCCESS), taskRule);
    }

    @Override
    public ReturnResult<List<TaskSignResponse>> signs(Long uid, String language) {

        List<UserTaskProgressDO> userTasks = taskVersionInfoService.findUserTasks(uid, language);
        List<UserTaskProgressDO> english = taskVersionInfoService.findUserTasks(uid, "en");

        for (int i = 0; i < userTasks.size(); i++) {
            if (StringUtils.isBlank(userTasks.get(i).getTitle())) {
                userTasks.get(i).setTitle(english.get(i).getTitle());
            }
        }

        List<TaskSignResponse> response = CopyUtils.copyList(userTasks, TaskSignResponse.class);
        for (int i = 0; i < userTasks.size(); i++) {
            response.get(i).setTaskId(userTasks.get(i).getTaskTemplateId());
        }

        response.forEach(item -> {
            item.setContent(item.getTitle());
            item.setTitle(null);
        });

        return ReturnResult.success(response);
    }

    @Override
    public ReturnResult<List<TaskRewardResponse>> signRewards(Long uid, String language) {
        List<TaskReward> taskRewardList = taskRewardService.findAll().stream()
                .skip(TaskCenter.STEP_THREE)
                .sorted(Comparator.comparingInt(TaskReward::getStep))
                .collect(Collectors.toList());
        if (ObjectUtils.isEmpty(taskRewardList)) {
            return ReturnResult.success(getInternational(language, InternationalCode.QUERY_SUCCESS), Collections.emptyList());
        }
        // 给定List数组大小减少内存开销
        List<TaskRewardResponse> flag = new ArrayList<>(taskRewardList.size());
        taskRewardList.forEach(item -> {
            TaskRewardResponse taskRewardResponse = new TaskRewardResponse();
            taskRewardResponse.setRewardType(item.getType());
            taskRewardResponse.setAmount(item.getAmount());
            taskRewardResponse.setDays(item.getStep() - TaskCenter.STEP_THREE);
            taskRewardResponse.setCurrency(item.getCurrency());
            flag.add(taskRewardResponse);
        });
        return ReturnResult.success(flag);
    }

    @Override
    public ReturnResult<TaskDataResponse> signTaskState(Long uid, String language) {

        // 先从缓存中获取
        String repeatKey = ActivityConstants.redisType.NEW_USER + uid;
        Object redisUserTaskProgress = RedisUtil.get(repeatKey);

        TaskUserProgress userTaskProgress;
        if (redisUserTaskProgress != null) {
            String taskProgress = (String) redisUserTaskProgress;
            userTaskProgress = JSON.parseObject(taskProgress, TaskUserProgress.class);
        } else {
            userTaskProgress = taskUserProgressService.findUserTaskProgress(uid);
            RedisUtil.set(ActivityConstants.redisType.NEW_USER + uid, JSON.toJSONString(userTaskProgress), 10L, TimeUnit.MINUTES);
        }

        TaskDataResponse taskDataResponse = new TaskDataResponse();
        // 如果在用户做任务的进度表中没有记录，他还能登录上，说明一定是老用户，或者新用户前三步都没有做完，那么都是0
        if (Objects.isNull(userTaskProgress) || userTaskProgress.getStep() <= TaskCenter.STEP_THREE) {
            taskDataResponse.setCompletion(TaskCenter.UN_FINISH);
            taskDataResponse.setContinuous(TaskCenter.UN_FINISH);
        } else {
            taskDataResponse.setCompletion(userTaskProgress.getStep() - TaskCenter.STEP_THREE);
            if (isContinue(userTaskProgress.getLeastFinishTime())) {
                log.debug("userTaskProgress:" + JSON.toJSONString(userTaskProgress));
                taskDataResponse.setContinuous(userTaskProgress.getFinishCount());
            } else {
                log.debug("当前的UTC-0的的时间是：[{}]", LocalDateTimeUtil.of(DateUtil.convertTimeZone(new Date(), ZoneId.of("UTC"))));
                taskDataResponse.setContinuous(0);
            }
        }
        return ReturnResult.success(taskDataResponse);
    }

    /**
     * 当前时间是不是上次领奖时间的下一天，如果是那么给用户展示连续的奖励，如果不是那么就展示签到一天的奖励
     *
     * @param leaseTime 上次领取奖励的时间
     * @return 是否是连续的两天
     */
    public static Boolean isContinue(Date leaseTime) {
        LocalDateTime lease = LocalDateTimeUtil.of(DateUtil.convertTimeZone(leaseTime, ZoneId.of("UTC")));
        LocalDateTime endOfTomorrow = LocalDateTimeUtil.endOfDay(lease.plusDays(1L));
        LocalDateTime now = LocalDateTimeUtil.of(DateUtil.convertTimeZone(new Date(), ZoneId.of("UTC")));
        return now.isBefore(endOfTomorrow);
    }

    @Override
    public ReturnResult<PageUtil<TaskOverviewResponse>> rewardOverview(Long uid, String language, PageQuery pageQuery) {
        PageUtil<TaskOverviewResponse> pageInfo = new PageUtil<>(pageQuery);
        List<TaskAwardLog> taskAwardLog = taskAwardLogService.findAwardByUid(uid);
        if (ObjectUtils.isEmpty(taskAwardLog)) {
            log.info("查询到用户：[{}]获得的奖励为null", uid);
            return ReturnResult.success();
        }
        List<TaskOverviewResponse> list = new ArrayList<>();

        // 可用币种求和
        if (taskAwardLog.stream().anyMatch(item -> Objects.equals(item.getAwardType(), TaskCenter.AVAILABLE_CURRENCY))) {
            taskAwardLog.stream()
                    .filter(item -> Objects.equals(item.getAwardType(), TaskCenter.AVAILABLE_CURRENCY))
                    .collect(Collectors.groupingBy(TaskAwardLog::getCurrency))
                    .forEach((key, value) -> {
                        TaskOverviewResponse taskOverviewResponse = new TaskOverviewResponse();
                        BigDecimal reduce = value.stream().map(TaskAwardLog::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
                        taskOverviewResponse.setAmount(reduce.setScale(6, RoundingMode.DOWN));
                        taskOverviewResponse.setCurrency(key);
                        taskOverviewResponse.setRewardType(TaskCenter.AVAILABLE_CURRENCY);
                        list.add(taskOverviewResponse);
                    });
        }
        // 盲盒求和
        if (taskAwardLog.stream().anyMatch(item -> Objects.equals(item.getAwardType(), TaskCenter.BLIND_BOX))) {
            BigDecimal reduce = taskAwardLog.stream()
                    .filter(x -> Objects.equals(x.getAwardType(), TaskCenter.BLIND_BOX))
                    .map(TaskAwardLog::getAmount)
                    .reduce(BigDecimal.ZERO, BigDecimal::add);
            TaskOverviewResponse taskOverviewResponse = new TaskOverviewResponse();
            taskOverviewResponse.setAmount(reduce);
            taskOverviewResponse.setRewardType(TaskCenter.BLIND_BOX);
            list.add(taskOverviewResponse);
        }
        // ET求和(这里etReward变量不能复用上面的taskOverviewResponse会发生fastjson循环引用，除非手动关闭fastjson循环引用)
        List<TaskEtRewards> etRewards = taskEtRewardsService.findEtRewardByUid(uid);
        if (CollUtil.isNotEmpty(etRewards)) {
            for (TaskEtRewards reward : etRewards) {
                if (reward.getCurrency().equals("et")) {
                    TaskOverviewResponse etReward = new TaskOverviewResponse();
                    etReward.setCurrency(reward.getCurrency());
                    etReward.setAmount(reward.getTotalFreeze().setScale(6, RoundingMode.DOWN));
                    etReward.setFrozen(reward.getTotalFreeze().subtract(reward.getUnfreeze()).setScale(6, RoundingMode.DOWN));
                    etReward.setAvailable(reward.getUnfreeze().setScale(6, RoundingMode.DOWN));
                    etReward.setRewardType(TaskCenter.ET_REWARD);
                    list.add(etReward);
                } else if (reward.getCurrency().equals("scs")) {
                    TaskOverviewResponse scsReward = new TaskOverviewResponse();
                    scsReward.setCurrency(reward.getCurrency());
                    scsReward.setAmount(reward.getTotalFreeze().setScale(6, RoundingMode.DOWN));
//                    scsReward.setFrozen(reward.getTotalFreeze().subtract(reward.getUnfreeze()).setScale(6, RoundingMode.DOWN));
//                    scsReward.setAvailable(reward.getUnfreeze().setScale(6, RoundingMode.DOWN));
                    scsReward.setRewardType(TaskCenter.SCS_REWARD);
                    list.add(scsReward);
                }
            }
        }
        // 合约手续费抵扣券
        if (taskAwardLog.stream().anyMatch(item -> Objects.equals(item.getAwardType(), TaskCenter.SWAP_FEE))) {
            BigDecimal reduce = taskAwardLog.stream()
                    .filter(x -> Objects.equals(x.getAwardType(), TaskCenter.SWAP_FEE))
                    .map(TaskAwardLog::getAmount)
                    .reduce(BigDecimal.ZERO, BigDecimal::add);
            TaskOverviewResponse taskOverviewResponse = new TaskOverviewResponse();
            taskOverviewResponse.setAmount(reduce);
            taskOverviewResponse.setRewardType(TaskCenter.SWAP_FEE);
            list.add(taskOverviewResponse);
        }
        // VIP升级券
        if (taskAwardLog.stream().anyMatch(item -> Objects.equals(item.getAwardType(), TaskCenter.VIP_REWARD))) {
            BigDecimal reduce = taskAwardLog.stream()
                    .filter(x -> Objects.equals(x.getAwardType(), TaskCenter.VIP_REWARD))
                    .map(TaskAwardLog::getAmount)
                    .reduce(BigDecimal.ZERO, BigDecimal::add);
            TaskOverviewResponse taskOverviewResponse = new TaskOverviewResponse();
            taskOverviewResponse.setAmount(reduce);
            taskOverviewResponse.setRewardType(TaskCenter.VIP_REWARD);
            list.add(taskOverviewResponse);
        }
        // 内存分页
        List<TaskOverviewResponse> page = list.stream()
                .sorted(Comparator.comparingInt(item -> sort(item.getRewardType())))
                .skip(pageInfo.getRowStart())
                .limit(pageInfo.getPageSize())
                .collect(Collectors.toList());
        pageInfo.setTotal((long) list.size());
        pageInfo.setItems(page);
        return ReturnResult.success(getInternational(language, InternationalCode.QUERY_SUCCESS), pageInfo);
    }

    @Override
    public ReturnResult<PageUtil<TaskRewardLogResponse>> rewardLogs(Long uid, String language, PageQuery query) {
        PageUtil<TaskRewardLogResponse> pageInfo = new PageUtil<>(query);
        List<TaskRewardLogResponse> list = CopyUtils.copyList(taskAwardLogService.findAwardByUid(uid), TaskRewardLogResponse.class);
        if (Objects.isNull(list)) {
            log.info("查询用户奖励表task_award_log 发现用户：[{}]并未获得任何奖励", uid);
            return ReturnResult.success();
        }
        List<TaskRewardLogResponse> page = list.stream()
                .sorted(Comparator.comparing(TaskRewardLogResponse::getCreateTime).reversed())
                .skip(pageInfo.getRowStart())
                .limit(pageInfo.getPageSize())
                .collect(Collectors.toList());
        pageInfo.setTotal((long) list.size());
        pageInfo.setItems(page);
        return ReturnResult.success(getInternational(language, InternationalCode.QUERY_SUCCESS), pageInfo);
    }

    @Override
    public ReturnResult<Boolean> receive(Long uid, String language, String account) {
        boolean redisLock = RedisUtil.setIfAbsent(RedisLockUtil.Activity.TASK_CENTER_REWARDS + uid, "1", 60);
        String internationalCode;
        try {
            if (redisLock) {
                internationalCode = taskVersionInfoService.receive(uid, account);
            } else {
                log.warn("用戶：[{}]正在进行领取奖励操作。。。", uid);
                internationalCode = InternationalCode.OPERATION_ERROR;
            }
        } finally {
            if (redisLock) {
                RedisUtil.delete(RedisLockUtil.Activity.TASK_CENTER_REWARDS + uid);
            }
        }
        return ReturnResult.success(getInternational(language, internationalCode), InternationalCode.OPERATION_SUCCESS.equals(internationalCode));
    }

    @Override
    public ReturnResult<Integer> receiveV2(Long uid, String language, String account) {
        boolean redisLock = RedisUtil.setIfAbsent(RedisLockUtil.Activity.TASK_CENTER_REWARDS + uid, "1", 60);
        String internationalCode;
        try {
            if (redisLock) {
                internationalCode = taskVersionInfoService.receiveV2(uid, account);
            } else {
                log.warn("用戶：[{}]正在进行领取奖励操作。。。", uid);
                internationalCode = InternationalCode.OPERATION_ERROR;
            }
        } finally {
            if (redisLock) {
                RedisUtil.delete(RedisLockUtil.Activity.TASK_CENTER_REWARDS + uid);
            }
        }

        if (Objects.equals(internationalCode, InternationalCode.TWITTER_ID_UNFOLLOW)
                || Objects.equals(internationalCode, InternationalCode.TWITTER_EXIST)
                || Objects.equals(internationalCode, InternationalCode.CHECK_FAILED)) {
            return ReturnResult.result(CODE_MAP.get(internationalCode), 500, getInternational(language, internationalCode));
        } else {
            return ReturnResult.success(getInternational(language, internationalCode), InternationalCode.OPERATION_SUCCESS.equals(internationalCode) ? 1 : 0);
        }
    }

    /**
     * 调整排序
     *
     * @param resource 原排序字段
     * @return 新的排序字段
     */
    public static Integer sort(Integer resource) {
        switch (resource) {
            case 1:
                return 1;
            case 2:
                return 5;
            case 3:
                return 3;
            case 4:
                return 0;
            case 5:
                return 2;
            case 6:
                return 4;
            default:
                return 5;
        }
    }
}
